﻿#include "TisCamera.h"
#include <iostream>
#include <QDebug>
#include <QMessageBox>

DShowLib::Grabber * DShowLibAutoInit::m_pGrabber = nullptr;
bool DShowLibAutoInit::m_libState = false;

DShowLibAutoInit::DShowLibAutoInit()
{
    if(m_libState == false)
    {
        //m_libState = DShowLib::InitLibrary((const char*) 0, -1);
        m_libState = DShowLib::InitLibrary();
    }
    if(m_libState)
    {
        qInfo() << "DShowLib::InitLibrary() success.";
        m_pGrabber = new DShowLib::Grabber();
        if(m_pGrabber)
        {
            qInfo() << "DShowLib::Grabber() success";
        }
    }
    else
    {
        qCritical() << "DShowLib::InitLibrary() failed. The ImagingSource Camera cannot work!";
    }
}

DShowLibAutoInit::~DShowLibAutoInit()
{
    if(m_libState)
    {
        DShowLib::ExitLibrary();
    }
}

//DShowLibAutoInit autoInit;


TisCameraInfo::TisCameraInfo(const QByteArray &name)
{
    m_TisCameraIterm = VideoCaptureDeviceItem::createInvalid();
    QString str(name);

    Grabber::tVidCapDevListPtr pVidCapDevList = DShowLibAutoInit::grabber()->getAvailableVideoCaptureDevices();
    for(unsigned int i = 0; i < pVidCapDevList->size(); i ++)
    { // 遍历所有的相机，找到名字相同的
        if(str == QString::fromStdString(pVidCapDevList->at(i).getUniqueName()))
        {
            m_TisCameraIterm = pVidCapDevList->at(i);
            break;
        }
    }
}

TisCameraInfo::TisCameraInfo(const TisCamera &camera)
{
    m_TisCameraIterm = camera.m_pGrabber->getDev();
}

TisCameraInfo::TisCameraInfo(const TisCameraInfo &other)
{
    this->m_TisCameraIterm = other.m_TisCameraIterm;
}

TisCameraInfo::TisCameraInfo(const VideoCaptureDeviceItem &item)
{
    m_TisCameraIterm = item;
}

QString TisCameraInfo::description() const
{
    std::string name = m_TisCameraIterm.getUniqueName();
    return QString::fromStdString(name);
}

QString TisCameraInfo::deviceName() const
{
    std::string name = m_TisCameraIterm.getUniqueName();
    return QString::fromStdString(name);
}

__int64 TisCameraInfo::deviceSerialNumber() const
{
    __int64 sn;
    m_TisCameraIterm.getSerialNumber(sn);
    return sn;
}

bool TisCameraInfo::driverVersion( int& major, int& minor, int& spnum, int& build )
{
    return m_TisCameraIterm.getDriverVersion(major, minor, spnum, build);
}

bool TisCameraInfo::isNull() const
{
    return !m_TisCameraIterm.isValid();
}

int TisCameraInfo::orientation() const
{
    return 0;
}

bool TisCameraInfo::operator!=(const TisCameraInfo &other) const
{
    return !(m_TisCameraIterm == other.m_TisCameraIterm);
}

TisCameraInfo & TisCameraInfo::operator=(const TisCameraInfo &other)
{
    m_TisCameraIterm = other.m_TisCameraIterm;
    return *this;
}

bool TisCameraInfo::operator==(const TisCameraInfo &other) const
{
    return m_TisCameraIterm == other.m_TisCameraIterm;
}

QList<TisCameraInfo> TisCameraInfo::availableCameras()
{
    QList<TisCameraInfo> x;
     return x;
}

TisCameraInfo TisCameraInfo::defaultCamera()
{
    Grabber::tVidCapDevListPtr pVidCapDevList = DShowLibAutoInit::grabber()->getAvailableVideoCaptureDevices();
    if( pVidCapDevList == nullptr || pVidCapDevList->empty() )
    {
        return TisCameraInfo("");
    }
    TisCameraInfo info(pVidCapDevList->at(0));
    return info;
}


TisCamera::TisCamera(QObject *parent)
    : QObject(parent),
      m_pGrabber(nullptr)
{
    if(DShowLibAutoInit::state())
    {
        m_pGrabber = new DShowLib::Grabber();
    }
}

void TisCamera::initVCDPropertyAccess()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        // Initialize the VCDProp object to access the properties of our ICImagingControl object
        m_VCDProp.init( m_pGrabber->getAvailableVCDProperties() );

        m_autoBrightness = false;
        if( m_VCDProp.isAutoAvailable( VCDID_Brightness ) )
        {
            m_autoBrightness = true;
        }

        m_autoWhiteBalance = false;
        if( m_VCDProp.isAutoAvailable( VCDID_WhiteBalance ) )
        {
            m_autoWhiteBalance = true;
        }
    }
}

bool TisCamera::autoBrightness(bool on)
{
    if( m_VCDProp.isAutoAvailable( VCDID_Brightness ) )
    {
        m_VCDProp.setAuto( VCDID_Brightness, on );
        return true;
    }
    return false;
}

bool TisCamera::autoWhiteBalance(bool on)
{
    if( m_VCDProp.isAutoAvailable( VCDID_WhiteBalance ) )
    {
        m_VCDProp.setAuto( VCDID_WhiteBalance, on );
        return true;
    }
    return false;
}

void TisCamera::setBrightness(int value)
{
    if( m_VCDProp.isAvailable( VCDID_Brightness ) )
    {
        m_VCDProp.setValue( VCDID_Brightness, value );
    }
}

bool TisCamera::setExpoureTime(int value)
{
    if( m_VCDProp.isAvailable( VCDID_Exposure ) )
    {
        m_VCDProp.setValue( VCDID_Exposure, value );
        return true;
    }
    return false;
}

double TisCamera::frameRate()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->getFPS( );
    }
    return 0.0;
}

int TisCamera::expoureTime()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        if( m_VCDProp.isAvailable( VCDID_Exposure ) )
        {
            return m_VCDProp.getValue( VCDID_Exposure );
        }
    }
    return 16666;
}

void TisCamera::setWhiteBalance(int red, int blue)
{
    if( m_VCDProp.isAvailable( VCDElement_WhiteBalanceRed ) )
    {
        m_VCDProp.setValue( VCDElement_WhiteBalanceRed, red );
    }
    if( m_VCDProp.isAvailable( VCDElement_WhiteBalanceBlue ) )
    {
        m_VCDProp.setValue( VCDElement_WhiteBalanceBlue, blue );
    }
}

bool TisCamera::onePush()
{
    if( m_VCDProp.isOnePushAvailable( VCDID_WhiteBalance ) )
    {
        m_VCDProp.push( VCDID_WhiteBalance );
        return true;
    }
    return false;
}

void TisCamera::initFrameRate()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        m_pFrameRateList = m_pGrabber->getAvailableFPS();
        if( !m_pFrameRateList->empty() )
        {
            m_pGrabber->setFPS ( m_pFrameRateList->at(0) );
            qDebug() << "FrameRate= " << m_pFrameRateList->at(0);
        }
    }
}

void TisCamera::setFrameRate(double fps)
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        m_pGrabber->setFPS( fps );
    }
}

bool TisCamera::startLive(bool show)
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->startLive(show);
    }
    return false;
}

bool TisCamera::isLive()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->isLive();
    }
    return false;
}

bool TisCamera::stopLive()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->stopLive();
    }
    return false;
}

bool TisCamera::suspendLive()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->suspendLive();
    }
    return false;
}

bool TisCamera::initFrameHandlerSink()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
    // Create a FrameTypeInfoArray data structure describing the allowed color formats.
        m_acceptedTypes = FrameTypeInfoArray::createOptimalTypesArray();
        m_pGrabber->setHWND( NULL );
        // Create the frame handler sink
        m_pFrameHandlerSink = FrameHandlerSink::create( m_acceptedTypes, 2 );

        // enable grab mode
        m_pFrameHandlerSink->setSnapMode( false );

        // Apply the sink to the grabber.
        m_pGrabber->setSinkType( m_pFrameHandlerSink );
        VideoFormatItem item = m_pGrabber->getVideoFormat();
        SIZE size = item.getSize();
        m_pListener = new TisCameraListener(this, size);
        // Register the pListener object for the frame ready event.
        //m_pGrabber->addListener( m_pListener, GrabberListener::eFRAMEREADY ||GrabberListener::eDEVICELOST  );
        m_pGrabber->addListener( m_pListener, GrabberListener::eFRAMEREADY |GrabberListener::eDEVICELOST );
        return true;
    }
    return false;
}

bool TisCamera::selectDevice()
{
    m_pGrabber->showDevicePage();
    if( m_pGrabber->isDevValid() )
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool TisCamera::isValid()
{
    return m_pGrabber->isDevValid();
}

bool TisCamera::setVideoFormat(QString format)//"Y800 (2592x1944)"
{
    bool ret = false;
    if( m_pGrabber->isDevValid() )
    {
        ret = m_pGrabber->setVideoFormat( format.toStdString() );
    }
    qDebug() << "m_pGrabber->setVideoFormat " << ret;
    return ret;
}

QStringList TisCamera::listVideoNorms()
{
    QStringList list;
    QString dev;
    Grabber::tVidNrmListPtr pVidNrmList;
    if( m_pGrabber->isVideoNormAvailableWithCurDev() )
    {
        // Query for all available video norms.
        pVidNrmList = m_pGrabber->getAvailableVideoNorms();
        for(unsigned int i = 0; i < pVidNrmList->size(); i ++)
        {
            dev = QString::fromStdString(pVidNrmList->at(i).toString());
            list << dev;
        }
    }
    return list;
}

QStringList TisCamera::listVideoFormats()
{
    QStringList list;
    QString format;
    Grabber::tVidFmtListPtr pVidFmtList = m_pGrabber->getAvailableVideoFormats();
    for(unsigned int i = 0; i < pVidFmtList->size(); i ++)
    {
        //qDebug() << pVidFmtList->at( i).c_str();
        format = QString::fromStdString(pVidFmtList->at(i).toString());
        list << format;
    }
    return list;
}

bool TisCamera::openDevice(const TisCameraInfo &info)
{
    bool ret = m_pGrabber->openDev( info.m_TisCameraIterm );
    return ret;
}

bool TisCamera::showVCDPropertyPage( )
{
    return m_pGrabber->showVCDPropertyPage( );
}

void TisCamera::closeDevice()
{
    m_pGrabber->stopLive();
    m_pGrabber->closeDev();
}

bool TisCamera::saveDeviceStateToFile( const std::string& filename)
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->saveDeviceStateToFile(filename);
    }
    return false;
}

bool TisCamera::loadDeviceStateFromFile(const std::string& filename, bool bOpenDev)
{
    if( m_pGrabber  )
    {
        return m_pGrabber->loadDeviceStateFromFile(filename, bOpenDev);
    }
    return false;
}

TisCamera::~TisCamera()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        // Stop live mode.
        m_pGrabber->stopLive();
       // m_pGrabber->saveDeviceStateToFile( "Q:\\device.xml" );
        // this call will also succeed if no device is open
        m_pGrabber->closeDev();
    }

    delete m_pGrabber;
}

TisCameraListener::TisCameraListener(TisCamera *pCamera, SIZE size)
    //: m_image(size.cx, size.cy, QImage::Format_RGB888)
{
    m_pCamera = pCamera;
}

TisCameraListener::~TisCameraListener()
{
}

void TisCameraListener::frameReady( DShowLib::Grabber& caller, smart_ptr<DShowLib::MemBuffer> pBuffer, DWORD FrameNumber )
{
    Q_UNUSED(caller);
    Q_UNUSED(FrameNumber);
    //qDebug() << "CameraListener::frameReady";
    FrameTypeInfo info = pBuffer->getFrameType();
    QSize size(info.dim.cx, info.dim.cy);
    unsigned char *pImage = pBuffer->getPtr();
    switch (info.getColorformat())
    {
    case eRGB32:
        //qDebug() << "RGB32ImageReceived";
        emit m_pCamera->RGB32ImageChanged(pImage, size);
        break;
    case eRGB24:
        //qDebug() << "RGB24ImageReceived";
        emit m_pCamera->RGB24ImageChanged(pImage, size);
        break;
    case eRGB8:
	case eY800:
        //qDebug() << "Mono8ImageReceived";
        emit m_pCamera->Mono8ImageChanged(pImage, size);
        break;
    default:
        break;
    }
}

void TisCameraListener::deviceLost( Grabber& caller )
{
    Q_UNUSED(caller);
    emit m_pCamera->deviceLost();
}



